﻿/*******************************************************************************************
 * Copyright (c) 2006-2009 Alex Robson, Rob Simmons, Craig Israel, and Rachel Twyford
 *
 * Use of this software in any form requires that you have both 
 * read and agreed to the following terms:
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the "Software"), 
 * to deal in the Software without restriction, including without limitation 
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions: 
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * Neither the name of Nvigorate nor the names of its contributors may 
 * be used to endorse or promote products derived from this software without 
 * specific prior written permission. 
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL ANY CONTRIBUTOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using Nvigorate.Common.Reflection;
using Nvigorate.Relational.Mapping.Interface;

namespace Nvigorate.Relational.Record
{
    /// <summary>
    /// The RecordCollectionBase is a simple implementation of the IRecordCollection
    /// interface. It's only intended for use with the standard Binder implementation.
    /// </summary>
    public abstract class RecordCollectionBase : IRecordCollection, IEnumerator<IRecord>
    {
        #region protected virtual Fields
        protected int _currentIndex = -1;
        protected List<IRecord> _recordList = new List<IRecord>();
        protected virtual List<IRecord> records
        {
            get
            {
                return _recordList;
            }
        }
        #endregion

        #region IRecordCollection Members

        /// <summary>
        /// Allows the addition of a record object to the collection
        /// </summary>
        /// <param name="record">IRecord to add</param>
        public virtual void Add(IRecord record)
        {
            bool valid = true;
            if (Count != 0)
            {
                if (record.FieldCount != this[0].FieldCount)
                    valid = false;
                if (valid)
                {
                    foreach (string fieldName in record.FieldNames)
                    {
                        if (!this[0].FieldNames.Contains(fieldName))
                        {
                            valid = false;
                            break;
                        }
                    }
                }
            }

            if(valid)
                _recordList.Add(record);
        }

        /// <summary>
        /// Adds a range of records to the collection
        /// </summary>
        /// <param name="records">A collection of IRecord objects</param>
        public virtual void AddRange(List<IRecord> records)
        {
            _recordList.AddRange(records);
        }

        /// <summary>
        /// Clears the record collection
        /// </summary>
        public virtual void Clear()
        {
            _recordList.Clear();
        }

        /// <summary>
        /// Returns the record at the given index
        /// </summary>
        /// <param name="index">The index of the record to return</param>
        /// <returns>IRecord</returns>
        public virtual IRecord this[int index]
        {
            get
            {
                return _recordList[index];
            }
            set
            {
                this._recordList[index] = value;
            }
        }
        
        /// <summary>
        /// Returns the number of records in the collection
        /// </summary>
        public virtual int Count
        {
            get { return _recordList.Count; }
        }

        /// <summary>
        /// Checks the collection for a matching record
        /// </summary>
        /// <param name="record">IRecord instance to check for</param>
        /// <returns>True if the list contains the IRecord, False if not</returns>
        public virtual bool Contains(IRecord record)
        {
            return _recordList.Contains(record);
        }

        /// <summary>
        /// Copies the collection of IRecords to an array of IRecord.
        /// </summary>
        /// <param name="records">The array to copy the collection into</param>
        /// <param name="index">The index to begin the copy at</param>
        public virtual void CopyTo(IRecord[] records, int index)
        {
            _recordList.CopyTo(records, index);
        }

        /// <summary>
        /// When overriden in an inheriting class, creates and adds a new IRecord to the collection.
        /// </summary>
        /// <returns>A new, empty IRecord</returns>
        public virtual IRecord CreateRecord()
        {
            throw new NotImplementedException();
        }

        object IEnumerator.Current
        {
            get { return this[(_currentIndex < 0) ? 0 : _currentIndex]; }
        }

        /// <summary>
        /// Returns the index of the current Record
        /// </summary>
        public virtual IRecord Current
        {
            get { return this[(_currentIndex < 0) ? 0 : _currentIndex]; }
        }

        /// <summary>
        /// Indicates if the end of collections has been reached
        /// </summary>
        public virtual bool EndOfRecords
        {
            get { return _currentIndex == _recordList.Count - 1 || _recordList.Count == 0; }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return records.GetEnumerator();
        }

        ///<summary>
        ///Returns an enumerator that iterates through the collection.
        ///</summary>
        ///
        ///<returns>
        ///A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
        ///</returns>
        ///<filterpriority>1</filterpriority>
        public virtual IEnumerator<IRecord> GetEnumerator()
        {
            foreach (IRecord record in records)
            {
                yield return record;
            }
        }

        /// <summary>
        /// Returns the first record in the set
        /// </summary>
        /// <returns>IRecord</returns>
        public virtual IRecord GetFirstRecord()
        {
            return this[0];
        }

        /// <summary>
        /// Returns the last record in the set
        /// </summary>
        /// <returns>IRecord</returns>
        public virtual IRecord GetLastRecord()
        {
            return this[Count - 1];
        }

        #region Implementation of IRecordCollection

        /// <summary>
        /// Returns the records matching the filter criteria provided via dictionary
        /// </summary>
        /// <param name="assignmentValues">The fields and corresponding values to filter by</param>
        /// <returns>List&gt;IRecord></returns>
        public virtual List<IRecord> GetRecordByAssignmentValues(Dictionary<IAssignmentPoint, object> assignmentValues)
        {
            FindAssignmentEvaluator<IRecord> evaluator = new FindAssignmentEvaluator<IRecord>(assignmentValues);
            return _recordList.FindAll(evaluator.RecordHasValues);
        }

        #endregion

        /// <summary>
        /// Returns all records as List &lt;IRecord&gt;
        /// </summary>
        /// <returns>List&lt;IRecord&gt;</returns>
        public virtual List<IRecord> GetRecordList()
        {
            return this._recordList;
        }

        /// <summary>
        /// Finds the index at which the IRecord occurs
        /// </summary>
        /// <param name="record">The IRecord to find the index for</param>
        /// <returns>Index of IRecord or -1 if IRecord does not exist</returns>
        public virtual int IndexOf(IRecord record)
        {
            for(int i = 0; i < Count; i++)
            {
                if(_recordList[i].Equals(record))
                    return i;
            }
            return -1;
        }

        /// <summary>
        /// Inserts an IRecord at the specified index
        /// </summary>
        /// <param name="index">The index to insert into</param>
        /// <param name="record">The IRecord to insert</param>
        public virtual void Insert(int index, IRecord record)
        {
            _recordList.Insert(index, record);
        }

        /// <summary>
        /// This only exists to make IRecordCollection compliant with IList. NOT USED
        /// </summary>
        public virtual bool IsReadOnly
        {
            get { return false;}
        }

        /// <summary>
        /// Returns the next record in the set
        /// </summary>
        /// <returns>IRecord</returns>
        public virtual bool MoveNext()
        {
            if (!EndOfRecords)
            {
                _currentIndex++;
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Returns the previous record in the set
        /// </summary>
        /// <returns>IRecord</returns>
        public virtual bool MovePrevious()
        {
            if (_currentIndex > 0)
            {
                _currentIndex--;
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Returns the name of the 
        /// </summary>
        public virtual string Name
        {
            get { return Reflector.GetCollectionElementType(_recordList).FullName; }
        }

        /// <summary>
        /// Retrieve schema of record layout from an instance when implemented
        /// </summary>
        /// <param name="schema">Object representing schema</param>
        public virtual void ReadSchema(ISourceMap schema)
        {
            throw new NotImplementedException();
        }
        
        /// <summary>
        /// Removes the specified IRecord from the collection
        /// </summary>
        /// <param name="record">The IRecord to remove</param>
        /// <returns>True if the IRecord exists and was successfully removed</returns>
        public virtual bool Remove(IRecord record)
        {
            return _recordList.Remove(record);
        }
        
        /// <summary>
        /// Removes the IRecord at the specified index
        /// </summary>
        /// <param name="index">The index to remove at</param>
        public virtual void RemoveAt(int index)
        {
            this._recordList.RemoveAt(index);
        }

        /// <summary>
        /// Sets the current index of the Record to 0 (the first Record)
        /// </summary>
        public virtual void Reset()
        {
            _currentIndex = -1;
        }

        #endregion

        #region Constructors
        public RecordCollectionBase()
        {
        }
        #endregion

        #region IDisposable Members

        public virtual void Dispose()
        {
            _recordList.Clear();
            _recordList = null;
        }

        #endregion

    }

    public class RecordCollection : RecordCollectionBase
    {

    }
}